/*
 * @Author: rock
 * @Date: 2025-05-23 23:12:35
 * @LastEditors: rock 
 * @LastEditTime: 2025-05-26 00:48:36
 * @FilePath: /002ThreadPool/src/threadpool.cpp
 * @Description: Ctrl+Num1-> For Document; Ctrl+Num2-> For Function
 *
 * Copyright (c) 2025 by rock, All Rights Reserved.
 */
#include "threadpool.h"

/***************************************************ThreadPool方法实现*********************************************************************** */
size_t ThreadPool::count_tasks_ = 0;        // 初始化为0, 任务计数
size_t ThreadPool::count_submit_tasks_ = 0; // 提交任务计数
const int TASK_THRESHHOLD = 4;              // 最大任务数量
const int TASK_CONDUCTER_WAIT_TIME = 1;     // 生产者等待时间, 过了这个时间线程池返回给生产者, 不能再等了, 任务队列还是满的
const int TASK_CONSUMER__WAIT_TIME = 600;     // 消费者不要再等了, 已经有5秒队列是空的了, 队列已经5秒没有生产者给任务了, 可以退出了
const int THREAD_THRESHHOLD = 10;           // 最大线程数量
const int THREAD_MAX_IDEL_TIME = 60;        // 空闲线程最大空闲时间, 超过这个时间回收资源, 单位,秒
// 构造
ThreadPool::ThreadPool()
    : initThreadSize_(0) // CPU核心数量
      ,
      taskSize_(0) // 开始的时候, 任务的数量是0
      ,
      taskQueMaxThreshHold_(TASK_THRESHHOLD) // 任务队列中的最大任务数量是1024个(TASK_THRESHHOLD)
      ,
      poolMode_(PoolMode::MOD_FIXED) // 固定数量模式的线程池
      ,
      isPoolRunning_(false) // 初始化线程池的运行状态, false不运行
      ,
      idleThreadSize_(0) // 初始化空闲线程的数量为0
      ,
      threadSizeThreshHold_(THREAD_THRESHHOLD) // 初始化最大线程数量, 线程池中的线程阈值
      ,
      cutThreadSize_(0) // 线程池中当前的线程个数
{
    LOG("ThreadPool() 初始化线程池");
}

// 析构
ThreadPool::~ThreadPool()
{
    LOG("线程池析构");
}

// 设置线程池工作的增长模式
void ThreadPool::setMode(PoolMode mode)
{
    if (checkRunnincState())
        return;
    poolMode_ = mode;
    if (mode == PoolMode::MOD_CACHED)
    {
        LOG("线程模式 Cached");
        return;
    }
    if (mode == PoolMode::MOD_FIXED)
    {
        LOG("线程模式 Fixed");
        return;
    }
}

// 设置task任务队列上限阈值
void ThreadPool::setTaskQueMaxThreshHold(int threshhold)
{
    if (checkRunnincState())
        return;
    taskQueMaxThreshHold_ = threshhold;
}

// 设置线程池cached模式下线程阈值
void ThreadPool::setThreadSizeThreshHold(int threshhold)
{
    if (checkRunnincState())
        return;
    if (poolMode_ == PoolMode::MOD_CACHED)
        threadSizeThreshHold_ = threshhold;
}

// 给线程池提交任务
// 用户给任务队列传入任务, 生产任务
// std::shared_ptr<Task> sp; 要求用户传入智能指针类型
Result ThreadPool::submitTask(std::shared_ptr<Task> sp)
{
    // 获取锁, 任务队列并不是线程安全的
    std::unique_lock<std::mutex> lock(taskQueMtx_);
    // // 线程的通信, 通过信号量等待任务队列有空任务, 然后把新任务交给任务队列
    // while (taskQue_.size() == taskQueMaxThreshHold_)
    // {
    //     //任务队列中的任务数量, 等于了最大任务数量, 也就是说不能再向任务队列中继续存放任务了
    //     notFull_.wait(lock);
    // }
    // //添加条件, 用户提交任务阻塞时间最长不能超过1秒, 否则任务提交失败, 说明任务队列现在是满的, 返回, 不能让用户一直阻塞
    // notFull_.wait(lock, [&]()->bool{
    //    return taskQue_.size() < taskQueMaxThreshHold_; //任务队列中的任务数量, 等于了最大任务数量, 也就是说不能再向任务队列中继续存放任务了
    // });
    // 如果有空余, 把任务放入任务队列中

    // //添加条件, 用户提交任务阻塞时间最长不能超过1秒, 否则任务提交失败, 说明任务队列现在是满的, 返回, 不能让用户一直阻塞
    bool ret_wait_for = notFull_.wait_for(
        lock,
        std::chrono::seconds(TASK_CONDUCTER_WAIT_TIME), // 等待1秒
        [&]() -> bool
        {
            LOG("等待的时候, 当前任务数 = " << taskQue_.size() << ", 任务队列最大任务数 = " << taskQueMaxThreshHold_);
            return taskQue_.size() < taskQueMaxThreshHold_; // 任务队列中的任务数量, 等于了最大任务数量, 也就是说不能再向任务队列中继续存放任务了
        });

    if (!ret_wait_for)
    {
        // 等待1秒钟, wait_for条件依然没有满足, 任务队列仍然没有空闲, 提交任务失败
        LOG("任务队列满, 任务提交失败, task queue is full, submit task failed --------------------------------");
        return Result(sp, false);
    }
    count_submit_tasks_++;
    sp->setId(count_submit_tasks_);//设置任务id
    LOG("任务提交成功, 提交的第" << count_submit_tasks_ << "个任务");

    
    taskQue_.emplace(sp);
    taskSize_++; // 任务数量加1

    // 因为新放了任务, 任务队列肯定不空了, 那么提醒消费者来消费任务notEmpty.notify
    notEmpty_.notify_all(); // 通知

    // 根据任务数量和空闲线程的数量, 判断是否需要创建新的线程出来
    // cached模式 处理任务小而急
    if (
        poolMode_ == PoolMode::MOD_CACHED         // 当前线程池是cached模式
        && taskSize_ > idleThreadSize_            // 当前任务数量大于空闲线程的数量
        && cutThreadSize_ < threadSizeThreshHold_ // 当前线程数量, 小于线程池可以创建线程的阈值, 线程池不能无限创建线程
    )
    {
        // 创建新线程
        //  创建thread线程对象的时候, 把线程函数给到thread线程对象
        int threadId = (int)cutThreadSize_;
        auto ptr = new Thread(std::bind(&ThreadPool::threadFunc, this, threadId), threadId);
        threads_.emplace(threadId, std::move(ptr)); // 资源转移
    }

    return Result(sp);
}

// 开启线程池
// 用户不传递参数有默认参数, 参数的数量是CPU核心数
// 用户穿了就是用户自定义数量
void ThreadPool::start(int initThreadSize)
{
    // 记录线程池初始线程的个数
    initThreadSize_ = initThreadSize;
    // 记录线程池当前拥有的线程个数
    cutThreadSize_ = initThreadSize;

    // 设置线程池启动状态
    isPoolRunning_ = true;

    // 创建线程对象std::vector<Thread *> threads_;
    for (int i = 0; i < initThreadSize_; i++)
    {
        // 创建thread线程对象的时候, 把线程函数给到thread线程对象
        int threadId = i+1;
        auto ptr = new Thread(std::bind(&ThreadPool::threadFunc, this, threadId), threadId);
        threads_.emplace(threadId, std::move(ptr)); // 资源转移
    }

    // 启动所有线程
    // 线程对象std::vector<Thread *> threads_;
    // 这里线程id是从1开始的
    for (int i = 1; i < initThreadSize_; i++)
    {
        // 需要执行一个线程函数
        threads_[i]->start();

        // 记录空闲线程, 开始创建的时候都是空闲线程
        idleThreadSize_++;
    }
}

// 定义线程函数
// 线程池中的所有线程, 从任务队列中消费任务
// 对应的线程函数结束, 也就代表这个线程可以回收了
void ThreadPool::threadFunc(int id)
{
    // 线程池中的每一个线程都有自己的线程id
    LOG("begin, 线程" << id << "执行, 线程tId:" << std::this_thread::get_id());

    // 添加时间戳
    auto lastTime = std::chrono::high_resolution_clock().now();

    // 线程池中的线程一直在取任务, 一直在做事情
    for (;;)
    {
        std::shared_ptr<Task> task = nullptr;
        {
            // 先获取锁
            std::unique_lock<std::mutex> lock(taskQueMtx_);

            // 等待notEmpty
            LOG("线程" << id << "开始空闲, 等待任务, 尝试获取新任务");

            // 超过空闲时间的60s, 新申请的线程回收掉
            // 超过initThreadSize_的线程要进行回收
            if (poolMode_ == PoolMode::MOD_CACHED)
            {
                // Cached模式
                while (taskQue_.size() > 0)
                {
                    if (std::cv_status::timeout == notEmpty_.wait_for(lock, std::chrono::seconds(1)))
                    {
                        // 条件变量超时返回
                        auto now = std::chrono::high_resolution_clock().now();
                        // 获取时间差
                        auto dur = std::chrono::duration_cast<std::chrono::seconds>(now - lastTime);

                        if (dur.count() >= THREAD_MAX_IDEL_TIME)
                        {
                            // 回收线程
                            // 记录线程数量的相关变量的值需要修改
                            // 把线程对象从线程列表容器中删除




                        }
                    }
                }
            }
            else
            {

                /***************************************等待TASK_CONSUMER__WAIT_TIME时间, 线程打破循环退出***************************************************/
                bool ret_wait_for = notEmpty_.wait_for(lock,
                                                       std::chrono::seconds(TASK_CONSUMER__WAIT_TIME), // 等待5秒没有任务就退出
                                                       [&]() -> bool
                                                       {
                                                           return taskQue_.size() > 0;
                                                       });
                // 空闲线程数量-1
                idleThreadSize_--;
                if (!ret_wait_for)
                {
                    LOG("线程" << id << "等待了6s, 还是没有接收到任务, 该线程退出");
                    break;
                }
                /***************************************等待TASK_CONSUMER__WAIT_TIME时间, 线程打破循环退出***************************************************/

                // // Fixed模式
                // notEmpty_.wait(lock,
                //                [&]() -> bool
                //                {
                //                    return taskQue_.size() > 0;
                //                });
            }

            LOG("线程" << id << "等待任务结束, 获取任务成功");

            // 从任务队列中取一个任务
            task = taskQue_.front();
            taskQue_.pop();
            taskSize_--;

            // 当前线程负责执行这个任务, 取走任务后就直接释放锁就可以了, 执行任务就不需要这把锁了
            // 出作用域就释放了锁
            // 通知
            // 如果依然有剩余任务, 继续通知其他线程执行任务
            if (taskQue_.size() > 0)
            {
                // 通知其他线程, 任务队列依然还有任务, 同志们继续取任务, 做任务
                notEmpty_.notify_all();
            }
            // 通知生产者队列不满, 可以放任务了
            notFull_.notify_all();
        }

        if (task != nullptr)
        {
            count_tasks_++;
            LOG("开始run..., 第 " << count_tasks_ << "个任务, 线程" << id << "执行");
            // task->run();
            task->exec();
        }
        // 线程执行完了任务, 就空闲了起来, 空闲任务计数+1;
        idleThreadSize_++;

        // 更新时间
        lastTime = std::chrono::high_resolution_clock().now();

        LOG("此时空闲线程的数量: " << idleThreadSize_);
    }

    LOG("  end, 线程" << id << "退出, 线程tId:" << std::this_thread::get_id());
}

// 检查pool的运行状态, 不允许启动以后再设置pool的运行状态
bool ThreadPool::checkRunnincState()
{
    return isPoolRunning_;
}

/***************************************************Thread方法实现*************************************************************/

// 启动线程
void Thread::start()
{
    // 执行一个线程函数
    LOG("线程池中的线程start()方法实现, 这里做了线程分离");
    // 创建一个线程, 执行一个线程函数
    // 把线程池传递过来的函数对象执行一下就可以了
    std::thread t(func_, threadId_); // 因为线程函数和线程对象有绑定关系, 所以线程对象要和主线程分离
    t.detach();                // 分离线程, linux下的pthread_thread
    // t.join();

    LOG("线程" << threadId_ << "的start方法执行完毕");
}

// Thread构造
Thread::Thread(ThreadFunc func, int id)
    : func_(func), threadId_(id)

{
    LOG("Thread::Thread()构造, 线程" << threadId_ << "被创建");
}
// Thread析构
Thread::~Thread()
{
    LOG("Thread::~Thread()析构, 线程" << threadId_ << "资源被回收");
}

/***************************************************Result方法实现*************************************************************/
Result::Result(std::shared_ptr<Task> task, bool isValid)
    : task_(task), isValid_(isValid)
{
    task_->setResult(this);
}
// 移动构造
Result::Result(Result &&other) noexcept
    : any_(std::move(other.any_))
// , isValid_(other.isValid_)
{
    isValid_.store(other.isValid_.load());
}

/***************************************************Task方法实现*************************************************************/
void Task::setResult(Result *res)
{
    result_ = res;
}

void Task::exec()
{
    if (result_ != nullptr)
    {
        result_->setVal(run()); // 多态调用, run()
    }
}

Task::Task()
    : result_(nullptr), id_(0)
{

}
Task::~Task()
{
    LOG("~Task析构, 第"<< id_ << "个任务被回收");
}

void Task::setId(int id)
{
    //设置任务id
    this->id_ = id;
}
int Task::getId()
{
    //获取id_
    return this->id_;
}